﻿//-------------------------------------------------------------------
//	Copyright (c) 2010-2014  Zhirnov Andrey
//	This file is part of the "UX Standard Lib" project.
//	See copyright notice in "UX_STL_Ext.h".
//-------------------------------------------------------------------

#ifndef _UXS_WIN_GL_WINDOW_H
#define _UXS_WIN_GL_WINDOW_H

#pragma once

#include "Window.h"

#ifdef PLATFORM_WINDOWS_SHELL
#ifdef UX_OPENGL_WINDOW_HANDLES


namespace UX_STL
{
namespace _platform_
{


	//
	// OpenGL Window
	//

	class UX_EXPORT GLWindow : public CWindow
	{
	public:
		struct TGLDescriptor
		{
			HGLRC					hSharedRC;
			e_glinit_flags::type	eFlags;
			uint8					uMSAASamples,		// Multisample Anti-Aliasing samples count or Coverage Samples (1..32)
									uColorSamples,		// Color Samples for CSAA (1..16)
									uColorBits,			// 24 or 32
									uDepthBits,			// 16, 24, 32
									uStencilBits;		// 0, 8
			bool					bVSync;
			///
			explicit
			TGLDescriptor(	e_glinit_flags::type e_flags = e_glinit_flags::DEFAULT,
								uint8	u_colors		= 32,
								uint8	u_zdepth		= 24,
								uint8	u_stencil		= 0,
								uint8	u_msaa			= 0,
								uint8	u_color_samples	= 0,
								bool	b_vsync			= false,
								HGLRC rc = null):
				eFlags(e_flags), uMSAASamples(u_msaa), uColorSamples(u_color_samples), uColorBits(u_colors),
				uDepthBits(u_zdepth), uStencilBits(u_stencil), bVSync(false), hSharedRC(rc) {}
		};

		struct TDescriptorExt
		{
			TDescriptor		sDesc;
			TGLDescriptor	sGLDesc;
			bool			bIgnoreGLInitErrors;
			///
			TDescriptorExt(): sDesc(), sGLDesc(), bIgnoreGLInitErrors(false) {}
			TDescriptorExt(const TDescriptor &d, const TGLDescriptor &g, bool ignore_err = false): sDesc(d), sGLDesc(g), bIgnoreGLInitErrors(ignore_err) {}
		};

		struct TCreateInThreadDataExt
		{
			GLWindow	*		pThis;
			TDescriptorExt		sDesc;
			string				sCaption;
			///
			TCreateInThreadDataExt(): pThis(null) {}
			TCreateInThreadDataExt(GLWindow *pthis, const TDescriptorExt &desc, uni_c_string cap):
				pThis(pthis), sDesc(desc), sCaption(cap) {}
		};

	protected:
		TGLContext		_sContext;
		TGLDescriptor	_sGLDescriptor;
		
	private:
		bool _CreateGL (const TDescriptorExt &sDesc, uni_c_string pCaption);

		static bool s_InitGL();
		static void _s_ThreadProcGL(void *pParam);

	public:
		GLWindow();
		~GLWindow();

		bool CreateGLInThread (Thread *pThread, const TDescriptorExt &sDesc, uni_c_string pCaption = uni_c_string(), const TWndClass &sWndClass = TWndClass());

		virtual bool Create (const TDescriptor &sDesc, uni_c_string pCaption = uni_c_string(), const TWndClass &sWndClass = TWndClass());
		virtual bool CreateGL (const TDescriptorExt &sDesc, uni_c_string pCaption = uni_c_string(), const TWndClass &sWndClass = TWndClass());
		virtual void Destroy ();
		virtual int  Loop ();
		
		bool IsContextCurrent()	const;
		bool MakeCurrent()	const;
		bool ResetContext()	const;
		bool SwapBuffers()	const;
		bool SetVSync(bool bEnabled);

		const TGLContext &		GetContext()	const	{ return _sContext; }
		TGLDescriptor const	&	GLDescriptor()	const	{ return _sGLDescriptor; }
	};


	
//-------------------------- GLWindow ----------------------------//
/*
=================================================
	проверяет установлен ли контекст
=================================================
*/
	inline bool GLWindow::IsContextCurrent() const
	{
		return ( wglGetCurrentContext() == _sHandles.hRC );
	}

/*
=================================================
	устанавливает текущий контекст рендера
=================================================
*/
	inline bool GLWindow::MakeCurrent() const
	{
		UX_GLWINDOW_SET_CONTEXT( &_sContext );
		if ( !IsContextCurrent() )
			return wglMakeCurrent( _sHandles.hDC, _sHandles.hRC ) == TRUE;
		return true;
	}
	
/*
=================================================
	сбрасывает контекст рендера
=================================================
*/
	inline bool GLWindow::ResetContext() const
	{
		UX_GLWINDOW_SET_CONTEXT( null );
		return wglMakeCurrent( _sHandles.hDC, null ) == TRUE;
	}

/*
=================================================
	выводит содерщимое буфера на экран
=================================================
*/
	inline bool GLWindow::SwapBuffers() const
	{
		return winapi::SwapBuffers( _sHandles.hDC ) == TRUE;
	}

#undef UX_GLWINDOW_SET_CONTEXT

//-------------------------------------------------------------------

}	// _platform_
}	// UX_STL


#endif	// UX_OPENGL_WINDOW_HANDLES
#endif	// PLATFORM_WINDOWS_SHELL
#endif	// _UXS_WIN_WINDOW_H